/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * $Id: WirelessData.cpp,v 1.8 2009-06-16 08:52:22 amaula Exp $
 *
 * \file
 * \brief Implementation of class CWirelessData
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#include "WirelessData.hpp"
#include "owndebug.h"

//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
using namespace MaCI::Wireless;
//*****************************************************************************
OWNDEBUG_INITIALIZE_MODULENUMBER(); // Initialize module print capability
//*****************************************************************************

CWirelessData::CWirelessData()
  : iTimestampPtr(NULL),
    iCommandPtr(NULL),
    iNodeSignalArray(),
    iNodeIDArray(),
    iNodeRangeArray(),
    iNodePositionArray(),
    iMeasurementIndexPtr(NULL),
    iWirelessChannelPtr(NULL),
    iLastElementType(-1)
{
}
//*****************************************************************************

CWirelessData::~CWirelessData()
{
  // Do any cleanups here.
}
//*****************************************************************************

bool CWirelessData::DecodeFrom(gim::binbag::CBinBag *aBinBag)
{
  bool result = true;
  const gim::binbag::TBinBlob *b = NULL;
  int previous_type = -1;
  
  // Store pointer and test it for NullNess. only overwrite if the
  // argument was non-NULL.
  if (aBinBag != NULL) 
    SetBinBagContainerPtr(aBinBag);

  // Parse
  if (iBinBagContainer && iBinBagContainer->Rewind()) {
    while( (b = iBinBagContainer->GetNextBinary()) && result ) {
      switch(b->type) {

      case KTypeTimestamp:
	if (iTimestampPtr == NULL && 
            b->size == sizeof(Common::TTimestamp)) {
	  iTimestampPtr = reinterpret_cast<const Common::TTimestamp *>(b->data);

	} else result = false;
	break;

      case KTypeCommand: {
        if (iCommandPtr == NULL && 
            b->size == sizeof(TCommand)) {
          iCommandPtr = reinterpret_cast<const TCommand *>(b->data); 

        } else result = false;
        break;
      }

      case KTypeNodeSignal: {        
        if (b->size == sizeof(TNodeSignal)) {
          iNodeSignalArray.push_back(reinterpret_cast<const TNodeSignal *>(b->data)); 

        } else result = false;
        break;
      }
      case KTypeNodeID: {        
        if (b->size == sizeof(TNodeID)) {
          iNodeIDArray.push_back(reinterpret_cast<const TNodeID *>(b->data)); 
          
        } else result = false;
        break;
      }
        
      case KTypeNodeRange: {
        if (b->size == sizeof(TNodeRange)) {
          iNodeRangeArray.push_back(reinterpret_cast<const TNodeRange *>(b->data)); 

        } else result = false;
        break;
      }
        
      case KTypeNodePosition: {
        if (b->size == sizeof(TNodePosition)) {
          iNodePositionArray.push_back(reinterpret_cast<const TNodePosition *>(b->data)); 

        } else result = false;
        break;
      }
      case KTypeMeasurementIndex: {
        if (iMeasurementIndexPtr == NULL && 
            b->size == sizeof(TMeasurementIndex)) {
          iMeasurementIndexPtr = reinterpret_cast<const TMeasurementIndex *>(b->data); 

        } else result = false;
        break;
      }
      case KTypeWirelessChannel:{
        if (iWirelessChannelPtr == NULL && 
            b->size == sizeof(TWirelessChannel)) {
          iWirelessChannelPtr = reinterpret_cast<const TWirelessChannel *>(b->data); 

        } else result = false;
        break;
      }
      default:
	// Unknown Type in BinBag. Do nothing.
	dPrint(10,"Unknown type %u, ignoring.", b->type);
        break;
      }
      
      // Store previous type
      previous_type = b->type;
    }
  } else result = false;

  // Store the result
  SetReadOnlyContainer(result);

  return result;
}
//*****************************************************************************

void CWirelessData::Reset()
{
  // Call base class Reset().
  CMaCIData::Reset();

  // Clean out. (Same values as in default constructor)
  iTimestampPtr = NULL;
  iCommandPtr = NULL;
  iNodeSignalArray.clear();
  iNodeRangeArray.clear();
  iNodePositionArray.clear();
  iNodeIDArray.clear();
  iMeasurementIndexPtr = NULL;
  iWirelessChannelPtr = NULL;
  iLastElementType = KTypeUnknown;
}
//*****************************************************************************

void CWirelessData::Print(const int l) const
{
  const gim::binbag::TBinBlob *b = NULL;
  // Parse
  if (iBinBagContainer && iBinBagContainer->Rewind()) {
    while( (b = iBinBagContainer->GetNextBinary())) {
      switch(b->type) {
      case KTypeTimestamp: {
	const Common::TTimestamp *ts = 
          reinterpret_cast<const Common::TTimestamp *>(b->data);
	dPrint(l,"TTimestamp: s=%d, us=%d", 
	       ts->timestamp_s,
	       ts->timestamp_us);
	break;
      }
        
      case KTypeCommand: {
	const TCommand *ts = 
          reinterpret_cast<const TCommand *>(b->data);
	dPrint(l,"TCommand: cmd=%d, data=%d", 
	       ts->cmd, ts->data);
	break;
      }

      case KTypeNodeSignal: {        
        const TNodeSignal *ns = reinterpret_cast<const TNodeSignal *>(b->data);
        dPrint(l,"KTypeNodeSignal dump:");
        ns->Print(l);
        break;
      }
        
      case KTypeNodeRange: {
        const TNodeRange *nr = reinterpret_cast<const TNodeRange *>(b->data); 
        dPrint(l,"KTypeNodeRange dump:");
        nr->Print(l);
        break;
      }
        
      case KTypeNodePosition: {
        const TNodePosition *np = reinterpret_cast<const TNodePosition *>(b->data); 
        dPrint(l,"KTypeNodePosition dump:");
        np->Print(l);
        break;
      }

      case KTypeMeasurementIndex: {
	const TMeasurementIndex *mi = 
          reinterpret_cast<const TMeasurementIndex *>(b->data);
	dPrint(l,"TMeasurementIndex: index=%d", 
	       mi->measurementIndex);
	break;
      }
      default:
	// Unknown Type in BinBag. Do nothing.
	dPrint(10,"Unknown type %u, ignoring.", b->type);
        break;
      }
    }
  }
}
//*****************************************************************************

bool CWirelessData::SetTimestamp(const Common::TTimestamp &aStamp)
{
  bool result = false;
  if (!IsReadOnlyContainer() && iTimestampPtr == NULL) {
    ADDELEMENT(Common::TTimestamp, KTypeTimestamp, iTimestampPtr, aStamp);
    result = true;
  }
  return result;
}
//*****************************************************************************

bool CWirelessData::SetCommand(const TCommand &aCmd)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iCommandPtr == NULL) {
    ADDELEMENT(TCommand, KTypeCommand, iCommandPtr, aCmd);
    result = true;
  }
  return result;
}
//*****************************************************************************

bool CWirelessData::AddNodeSignal(const TNodeSignal &aNodeSignal)
{  
  bool result = false;
  if (!IsReadOnlyContainer()) {
    // Add to container
    const gim::binbag::TBinBlob *b = 
      iBinBagContainer->AddBinary(KTypeNodeSignal, 
                                  (const char *)&aNodeSignal, 
                                  sizeof(TNodeSignal)); 
    
    // Typecast
    const TNodeSignal *ns = reinterpret_cast<const TNodeSignal *>(b->data); 

    // Store.
    iNodeSignalArray.push_back(ns);
    SetLastElementType(KTypeNodeSignal);

    result = true;
  }
  return result;
}
//*****************************************************************************
bool CWirelessData::AddNodeID(const TNodeID &aNodeID)
{  
  bool result = false;
  if (!IsReadOnlyContainer()) {
    // Add to container
    const gim::binbag::TBinBlob *b = 
      iBinBagContainer->AddBinary(KTypeNodeID, 
                                  (const char *)&aNodeID, 
                                  sizeof(TNodeID)); 
    
    // Typecast
    const TNodeID *ni = reinterpret_cast<const TNodeID *>(b->data); 

    // Store.
    iNodeIDArray.push_back(ni);
    SetLastElementType(KTypeNodeID);

    result = true;
  }
  return result;
}
//*****************************************************************************

bool CWirelessData::AddNodeRange(const TNodeRange &aNodeRange)
{
  bool result = false;
  if (!IsReadOnlyContainer()) {
    // Add to container
    const gim::binbag::TBinBlob *b = 
      iBinBagContainer->AddBinary(KTypeNodeRange, 
                                  (const char *)&aNodeRange, 
                                  sizeof(TNodeRange)); 
    
    // Typecast
    const TNodeRange *nr = reinterpret_cast<const TNodeRange *>(b->data); 

    // Store.
    iNodeRangeArray.push_back(nr);
    SetLastElementType(KTypeNodeRange);

    result = true;
  }
  return result;
}
//*****************************************************************************

bool CWirelessData::AddNodePosition(const TNodePosition &aNodePosition)
{
  bool result = false;
  if (!IsReadOnlyContainer()) {
    // Add to container
    const gim::binbag::TBinBlob *b = 
      iBinBagContainer->AddBinary(KTypeNodePosition, 
                                  (const char *)&aNodePosition,
                                  sizeof(TNodePosition)); 
    
    // Typecast
    const TNodePosition *np = reinterpret_cast<const TNodePosition *>(b->data); 

    // Store.
    iNodePositionArray.push_back(np);
    SetLastElementType(KTypeNodePosition);

    result = true;
  }
  return result;
}
//*****************************************************************************

bool CWirelessData::SetMeasurementIndex(const TMeasurementIndex &aMeasurementIndex)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iMeasurementIndexPtr == NULL) {
    ADDELEMENT(TMeasurementIndex, KTypeMeasurementIndex, iMeasurementIndexPtr, aMeasurementIndex);
    result = true;
  }
  return result;
}
//*****************************************************************************

bool CWirelessData::AddWirelessChannel(const TWirelessChannel &aChannel)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iWirelessChannelPtr == NULL) {
    ADDELEMENT(TWirelessChannel, KTypeWirelessChannel, iWirelessChannelPtr, aChannel);
    result = true;
  }
  return result;
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

const MaCI::Common::TTimestamp *CWirelessData::GetTimestamp(void) const
{
  return iTimestampPtr;
}
//*****************************************************************************

const TCommand *CWirelessData::GetCommand(void) const
{
  return iCommandPtr;
}
//*****************************************************************************

const TNodeSignalPtrArray &CWirelessData::GetNodeSignalArray(void) const
{
  return iNodeSignalArray;
}
//*****************************************************************************

const TNodeIDPtrArray &CWirelessData::GetNodeIDArray(void) const
{
  return iNodeIDArray;
}
//*****************************************************************************

const TNodeRangePtrArray &CWirelessData::GetNodeRangeArray(void) const
{
  return iNodeRangeArray;
}
//*****************************************************************************

const TNodePositionPtrArray &CWirelessData::GetNodePositionArray(void) const
{
  return iNodePositionArray;
}
//*****************************************************************************

const TMeasurementIndex *CWirelessData::GetMeasurementIndex(void) const
{
  return iMeasurementIndexPtr;
}
//*****************************************************************************

const TWirelessChannel *CWirelessData::GetWirelessChannel(void) const
{
  return iWirelessChannelPtr;
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

#ifdef COMPILE_WIRELESSDATA_STANDALONE_MAIN
#include <string>

int main(void)
{
  using namespace MaCI::Wireless;
  gim::binbag::CBinBag bb;
  CWirelessData A;
  CWirelessData B;
  bool r;

  printf("Carry out Encoding/Decoding test.\n");

  printf("Encoding...\n");
  // Do Encoding 
  A.EncodeTo(&bb);
  
  printf("Encode: Timestamp(1,2) ... ");
  r = A.SetTimestamp(MaCI::Common::TTimestamp(1, 2));
  assert(r == true);

  r = A.SetMeasurementIndex(MaCI::Wireless::TMeasurementIndex(666));
  assert (r == true);
  printf("OK.\n");

  r = A.AddWirelessChannel(MaCI::Wireless::TWirelessChannel(6));
  /**
   * \todo Add test sections for TWirelessEvent and TCommand
   */
  //////////////////////////////////////////////////////////
  printf("Decoding...\n");
  // Do Decoding
  B.DecodeFrom(&bb);
  printf("Decode: GetTimestamp() = (%d, %d)\n", 
	 B.GetTimestamp()->timestamp_s, 
	 B.GetTimestamp()->timestamp_us);
  assert(B.GetTimestamp()->timestamp_s == 1);
  assert(B.GetTimestamp()->timestamp_us == 2);
  
  printf("Decode: GetMeasurementIndex() = %d\n",
         B.GetMeasurementIndex()->measurementIndex);
  assert(B.GetMeasurementIndex()->measurementIndex == 666);
  
  printf("Decode: GetWirelessChannel() = %d\n",
         B.GetWirelessChannel()->channel);
  assert(B.GetWirelessChannel()->channel == 6);
  /**
   * \todo Add test sections for TWirelessEvent and TCommand
   */

  printf("Test complete.\n");
  

}
#endif
//*****************************************************************************
//*****************************************************************************
